package com.wangshili.common.aspect;

import java.util.Arrays;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 日志切面
 * 1.要将类交给spring管理@Component
 * 2.注解为切面类@Aspect
 * 3.可以使用@Order注解指定切面的优先级，值越小优先级越高
 * @author wangshili
 *
 *
 */
@Order(2)
@Aspect
//@Component
public class AspectTest {
	private static final Logger log = 
			LoggerFactory.getLogger(AspectTest.class);
	/**
	 * 给Log业务实现类添加切点（里面所有的方法都会切入，一个方法就称为连接点）
	 * 多个方法的集合就是切入点
	 * 加在logPointCut方法上是为了方便复用，因为有不同的通知方式
	 * bean小写，实现类的第一个字母默认小写
	 */
	@Pointcut("bean(sysLogServiceImpl)")//匹配SysLogServiceImpl的bean对象
	public void logPointCut() {}
	
	/**
	 * 环绕通知，包含了所有的通知，优先级最高，需要携带ProceedingJoinPoint类型参数
	 * Joinpoint就是连接点，连接点就是被执行的方法，可以对方法执行前后进行相应的操作
	 * ProceedingJoinPoint 是Joinpoint的实现类
	 * @throws Throwable 
	 */
	@Around("logPointCut()")
	public Object around(ProceedingJoinPoint   jc) throws Throwable {
		String methodName = jc.getSignature().getName();//获取执行方法名
		try {
			//方法执行前通知，也叫前置通知
			log.debug("method:"+methodName+"-startTime:"+System.currentTimeMillis());
			//获取传递的参数
			log.debug("method:"+methodName+"-arg[]:"+Arrays.toString(jc.getArgs())+System.currentTimeMillis());
			//执行当前方法
			Object result = jc.proceed();
			//返回通知
			log.debug("method:"+methodName+"-return:"+result+System.currentTimeMillis());
			//方法执行后通知，也叫后置通知
			log.debug("method:"+methodName+"-endTime:"+System.currentTimeMillis());
			return result;
		} catch (Exception e) {
			// 异常处理，也叫异常通知
			log.error(e.getMessage());
			throw e;
		}
	}	
}

//@Component
@Aspect
 class SysTimeAspect {
        @Pointcut("bean(sysUserServiceImpl)")
        public void doTime(){}

        //前置通知
        @Before("doTime()")
        public void doBefore(JoinPoint jp){
                System.out.println("time doBefore()");
        }
        
        //后置通知
        @After("doTime()")
        public void doAfter(){
                System.out.println("time doAfter()");
        }
        
        //返回通知
        /**核心业务正常结束时执行* 说明：假如有after，先执行after,再执行returning*/
        @AfterReturning("doTime()")
        public void doAfterReturning(){
                System.out.println("time doAfterReturning");
        }
        
        //异常通知
        /**核心业务出现异常时执行说明：假如有after，先执行after,再执行Throwing*/
        @AfterThrowing("doTime()")
        public void doAfterThrowing(){
                System.out.println("time doAfterThrowing");
        }

        @Around("doTime()")
        public Object doAround(ProceedingJoinPoint jp)
                        throws Throwable{
               System.out.println("doAround.before");
               Object obj;
         try{
                 obj=jp.proceed();
                 System.out.println("doAround.after");
	         }catch(Throwable e){
	          System.out.println(e.getMessage());
	          throw e;
	         }
                return obj;
        }

}
